#include <string.h>
#include <stdio.h>
#include "xlog.h"

#ifdef LOG_ENABLE

#define LOG_LINE_BUF_SIZE  128

#ifndef LOG_NEWLINE_SIGN
    #define LOG_NEWLINE_SIGN              "\r\n"
#endif

char s_log_buffer[LOG_LINE_BUF_SIZE + 1] = {0};

static uint32_t log_strcpy(uint32_t cur_len, char *dst, const char *src)
{
    const char *src_old = src;

    while (*src != 0)
    {
        /* make sure destination has enough space */
        if (cur_len++ < LOG_LINE_BUF_SIZE)
        {
            *dst++ = *src++;
        }
        else
        {
            break;
        }
    }
    return src - src_old;
}

/**
 * dump the hex format data to log
 *
 * @param tag name for hex object, it will show on log header
 * @param width hex number for every line, such as: 16, 32
 * @param buf hex buffer
 * @param size buffer size
 */
void log_hexdump(const char *tag, uint32_t width, uint8_t *buf, uint32_t size)
{
#define __is_print(ch)       ((unsigned int)((ch) - ' ') < 127u - ' ')

    uint32_t i, j;
    uint32_t log_len = 0, name_len = strlen(tag);
    char *log_buf = NULL, dump_string[8];
    int fmt_result;

    /* get log buffer */
    log_buf = s_log_buffer;

    /* lock output */
    // output_lock();

    for (i = 0, log_len = 0; i < size; i += width)
    {
        /* package header */
        if (i == 0)
        {
            log_len += log_strcpy(log_len, log_buf + log_len, "D/HEX ");
            log_len += log_strcpy(log_len, log_buf + log_len, tag);
            log_len += log_strcpy(log_len, log_buf + log_len, ": ");
        }
        else
        {
            log_len = 6 + name_len + 2;
            memset(log_buf, ' ', log_len);
        }
        fmt_result = snprintf(log_buf + log_len, LOG_LINE_BUF_SIZE, "%04X-%04X: ", i, i + width - 1);
        /* calculate log length */
        if ((fmt_result > -1) && (fmt_result <= LOG_LINE_BUF_SIZE))
        {
            log_len += fmt_result;
        }
        else
        {
            log_len = LOG_LINE_BUF_SIZE;
        }
        /* dump hex */
        for (j = 0; j < width; j++)
        {
            if (i + j < size)
            {
                snprintf(dump_string, sizeof(dump_string), "%02X ", buf[i + j]);
            }
            else
            {
                strncpy(dump_string, "   ", sizeof(dump_string));
            }
            log_len += log_strcpy(log_len, log_buf + log_len, dump_string);
            if ((j + 1) % 8 == 0)
            {
                log_len += log_strcpy(log_len, log_buf + log_len, " ");
            }
        }
        log_len += log_strcpy(log_len, log_buf + log_len, "  ");
        /* dump char for hex */
        for (j = 0; j < width; j++)
        {
            if (i + j < size)
            {
                snprintf(dump_string, sizeof(dump_string), "%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
                log_len += log_strcpy(log_len, log_buf + log_len, dump_string);
            }
        }
        /* overflow check and reserve some space for newline sign */
        if (log_len + strlen(LOG_NEWLINE_SIGN) > LOG_LINE_BUF_SIZE)
        {
            log_len = LOG_LINE_BUF_SIZE - strlen(LOG_NEWLINE_SIGN);
        }
        /* package newline sign */
        log_len += log_strcpy(log_len, log_buf + log_len, LOG_NEWLINE_SIGN);
        /*add string end sign*/
        log_buf[log_len] = '\0';
        /* do log output */
        printf("%s", log_buf);
    }
    /* unlock output */
    // output_unlock();
}

#endif

